

#include <windows.h>  // keep this on top level or you'll get 'IService' ambiguous sysmbol error.

#include "WorkerThread.h"
#include "Log.h"
#include "World/World.h"
#include "World/Screen.h"
#include "Events.h"

using namespace GTA;

WorkerThread* _WorkerThread; // todo: remove globals

WorkerThread::WorkerThread()
{
	SetName("GTAScript.WorkerThread");
	_WorkerThread = this;
	IsScriptsActive = false;
	GTA::Log::Debug("WorkerThread Constructor");
	Scripts = nullptr;
	LoadScripts();
}

WorkerThread::~WorkerThread()
{
	GTA::Log::Debug("WorkerThread Destructor");
	UnloadScripts();
}

void WorkerThread::OnStart()
{
	GTA::Log::Debug("WorkerThread OnStart");
	//LoadScripts(); // crashes here for some reason (crash occurs when keyboard hook callback is raised), works fine in runtick or constructor. strange
}

void WorkerThread::RunTick()
{
	CheckKeys();
	if (IsScriptsActive) { if (Scripts) Scripts->CallEvents(); }
};

void WorkerThread::OnKill()
{
	GTA::Log::Debug("WorkerThread OnKill");
	UnloadScripts();
}



void WorkerThread::CheckKeys()
{ 
	if (GetAsyncKeyState(VK_CONTROL)!= 0)
	{ // CTRL heald
		if ((GetAsyncKeyState(VK_F11) & 1) != 0)
		{  // CTRL-F11, unload script domain
			if (IsScriptsActive)
			{
				UnloadScripts();
			}
		}
		if ((GetAsyncKeyState(VK_F12) & 1) != 0)
		{ // CTRL-F12, load script domain
			if (!IsScriptsActive)
			{
				LoadScripts();
			}
		}
	}
};

unsigned int __stdcall LoadScriptsProlog(void*)
{ // GLOBAL, message thread (for hooks)
	
	WorkerThread* worker = _WorkerThread;
	if (ScriptDomain::Instance == nullptr) GTA::ScriptDomain^ ScriptDomain = gcnew GTA::ScriptDomain();
	if (ScriptDomain::Instance->environmentBuilt) {worker->Scripts = ScriptDomain::Instance->scriptmanager; return 0;}
	ScriptDomain::Instance->CreateScriptDomain(); // create the actual scriptdomain that scripts will load into 
	GTA::ScriptManager^ ScriptManager = ScriptDomain::Instance->CreateScriptManager(ScriptDomain::GetScriptDomain()); 
	worker->Scripts = ScriptDomain::Instance->scriptmanager;
	ScriptManager->InitalizeHooks(worker->DllHandle,worker->DllThreadId);
	ScriptManager->OnStart();

	//System::Windows::Forms::Application::Run(); // for keyboard hook (windows messages) 
	while (worker->IsScriptsActive)
	{
		MSG msg;
		PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
		Sleep(33);
	}
	GTA::Log::Message("Message thread terminating.");
	return 0;
}

void WorkerThread::UnloadScripts()
{
	if (!IsScriptsActive) return;
	IsScriptsActive = false;
	GTA::Log::Message("Unloading Scripts.");
	GTA::Screen::PrintString("Unloading Scripts!",2000);
	if (ScriptDomain::Instance == nullptr) return;
	ScriptDomain::Instance->UnloadScriptDomain(); 
	Scripts = nullptr;
	GTA::Screen::PrintString("Scripts Unloaded!",2000);
}

void WorkerThread::LoadScripts()
{
	if (IsScriptsActive) return;
	GTA::Log::Message("Loading Scripts.");
	GTA::Screen::PrintString("Loading Scripts!",2000);
	unsigned int threadid;
	HANDLE handle = CreateThread(NULL, 0,(LPTHREAD_START_ROUTINE)&LoadScriptsProlog, 0, 0, (LPDWORD)&threadid);
	if (handle == 0 || handle == INVALID_HANDLE_VALUE) return;
	CloseHandle(handle);
	IsScriptsActive = true;
	GTA::Screen::PrintString("Scripts Loaded!",2000);
}

